#include "include/lyricsearchwidget.h"
#include"include/lyrictool.h"
#include "ui_lyricsearchwidget.h"

QString LyricSearchWidget::ttserver="http://ttlrcct.qianqian.com/dll/lyricsvr.dll";

LyricSearchWidget::LyricSearchWidget(const QString &track,QWidget *parent) :
    QWidget(parent),
    ui(new Ui::LyricSearchWidget)
{
    ui->setupUi(this);
    setFixedSize(353,334);
    trackName=track;
    QStringList info=LyricTool::trackInfo(trackName);
    if(info.size()>1)
    {
        ar.append(info[0]);
        ti.append(info[1]);
    }
    ids=QStringList();
    artists=QStringList();
    titles=QStringList();
    treeItemIno=QMap<QString,int>();
    ui->artInput->setText(ar);
    ui->titInput->setText(ti);
    ui->downBtn->setEnabled(false);

    netManager=new QNetworkAccessManager(this);
    netManager->setNetworkAccessible(QNetworkAccessManager::Accessible);
    request=new QNetworkRequest();
    if((!ti.isEmpty())&&(!ar.isEmpty()))
    {
        searchReply=searchLyric(ti,ar);
        connect(ui->closeBtn,SIGNAL(clicked()),this,SLOT(close()));
    }
    else
        this->show();
    connect(ui->searchBtn,SIGNAL(clicked()),this,SLOT(onSearchClicked()));
    connect(ui->downBtn,SIGNAL(clicked()),this,SLOT(onDownClicked()));
    connect(ui->artInput,SIGNAL(textChanged(QString)),this,SLOT(onArTextChanged(QString)));
    connect(ui->titInput,SIGNAL(textChanged(QString)),this,SLOT(onTiTextChanged(QString)));
    connect(ui->treeWidget,SIGNAL(itemClicked(QTreeWidgetItem*,int)),
            this,SLOT(onItemClicked(QTreeWidgetItem*,int)));
    connect(ui->treeWidget,SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),
            this,SLOT(onItemDblClicked(QTreeWidgetItem*,int)));
    connect(ui->closeBtn,SIGNAL(clicked()),this,SLOT(close()));
}
LyricSearchWidget::~LyricSearchWidget()
{
    delete ui;
}

void LyricSearchWidget::onArTextChanged(QString s)
{
    ar.clear();
    ar.append(s);
    if(ar.isEmpty())
    {
        ui->searchBtn->setEnabled(false);
    }
    else if(!ti.isEmpty())
        ui->searchBtn->setEnabled(true);
}

void LyricSearchWidget::onTiTextChanged(QString s)
{
    ti.clear();
    ti.append(s);
    if(ti.isEmpty())
    {
        ui->searchBtn->setEnabled(false);
    }
    else if(!ar.isEmpty())
        ui->searchBtn->setEnabled(true);
}

QNetworkReply* LyricSearchWidget::searchLyric(const QString &title, const QString &artist)
{
    ui->infoLbl->clear();
    QString ar_str=artist.toLower().replace(" ","").replace("'","");
    QString ti_str=title.toLower().replace(" ","").replace("'","");
    char *ar_cstr=hexString(ar_str);
    char *ti_cstr=hexString(ti_str);

    QString server(ttserver);
    server.append("?sh?Artist=");
    server.append(ar_cstr);
    server.append("&Title=");
    server.append(ti_cstr);
    server.append("&Flags=0");
    request->setUrl(QUrl(server));
    searchReply=netManager->get(*request);
    connect(searchReply,SIGNAL(finished()),this,SLOT(onSearchFinished()));
    free(ar_cstr);
    free(ti_cstr);
    return searchReply;
}

QNetworkReply* LyricSearchWidget::downloadLyric(const QString &id, const QString &title, const QString &artist)
{
    QString server(ttserver);
    QString info(artist);
    info.append(title);
    server.append("?dl?Id=");
    server.append(id);
    server.append("&Code=");
    qint32 code=getCode(id.toInt(),info.toStdString().c_str());
    server.append(QString::number(code));
    server.append("&uid=01");
    char ts[32];
    int mac=qrand();
    sprintf(ts,"&mac=%012x",mac);
    server.append(ts);
    request->setUrl(QUrl(server));
    //    qDebug()<<server<<"\n";
    downReply=netManager->get(*request);
    connect(downReply,SIGNAL(finished()),SLOT(onDownloadFinished()));
    return downReply;
}

void LyricSearchWidget::parseXml(const QByteArray &array)
{
    //    qDebug()<<array<<"\n";
    ids.clear();
    artists.clear();
    titles.clear();
    treeItemIno.clear();
    QString errorMessage;
    int errorLine,errorColumn;
    QDomDocument document;
    if(!document.setContent(array,false,&errorMessage,&errorLine,&errorColumn))
    {
        qDebug()<<errorMessage<<" Line "<<errorLine<<" Column "<<errorColumn;
        return;
    }
    QDomElement element=document.documentElement();
    QDomNodeList lyricsList=element.elementsByTagName("lrc");
    for(int j=0;j<lyricsList.size();j++)
    {
        QDomElement lrc=lyricsList.at(j).toElement();
        ids<<lrc.attribute("id");
        artists<<lrc.attribute("artist");
        titles<<lrc.attribute("title");
        treeItemIno.insert(ids[j],j);
    }
}

void LyricSearchWidget::onSearchFinished()
{
    parseXml(searchReply->readAll());
    if(ids.size()<1)
    {
        ui->infoLbl->setText(QObject::tr("No Search Result."));
        emit searchResult(false);
    }
    else
    {
        ui->treeWidget->clear();
        QTreeWidgetItem *item;
        for(int i=0;i<ids.size();i++)
        {
            QStringList infoList(ids[i]);
            infoList<<artists[i]<<titles[i];
            item=new QTreeWidgetItem(infoList);
            ui->treeWidget->addTopLevelItem(item);
        }
    }
    if(!this->isVisible())
        this->show();
}

void LyricSearchWidget::onDownloadFinished()
{
    QDir dir;
    QString lyricDir=QDir::homePath().append("/Minip/lyrics");
    if(!dir.exists(lyricDir))
    {
        if(!dir.mkpath(lyricDir))
        {
            qDebug()<<"Create Lyric Directory Failed!\n";
            return;
        }
    }
    QString fileName=LyricTool::lyricFileName(trackName);
    QFile f(fileName);
    if(!f.open(QIODevice::WriteOnly|QIODevice::Text))
        return;
    QTextStream stream(&f);
    stream<<downReply->readAll();
    f.close();
    ui->infoLbl->setText(QObject::tr("Lyrics Downloaded!Close Dialog Now."));
    emit downFinished(trackName);
}

qint32 LyricSearchWidget::getCode(int id, const char *data)
{
    //this function is modified from osdlyrics
    quint32 id1 = id & 0xff;
    quint32 id2 = (id >> 8) & 0xff;
    quint32 id3 = (id >> 16) & 0xff;
    quint32 id4 = (id >> 24) & 0xff;

    if (id3 == 0) id3 = ~id2 & 0xff;
    if (id4 == 0) id4 = ~id1 & 0xff;
    qint32 encoded_id = (id1 << 24) | (id3 << 16) | (id2 << 8) | id4;
    qint32 encoded_data = 0;
    size_t len = strlen(data);
    int i;
    for (i = len - 1; i >= 0; i--)
        encoded_data = encoded_data + data[i] + (encoded_data << (i % 2 + 4));
    qint32 encoded_data2 = 0;
    for (i = 0; i < len; i++)
        encoded_data2 = encoded_data2 + data[i] + (encoded_data2 << (i % 2 + 3));
    qint32 ret = ((encoded_data ^ encoded_id) + (encoded_data2 | id)) * (encoded_data2 | encoded_id);
    ret = ret * (encoded_data ^ id);
    return ret;
}

void LyricSearchWidget::onItemClicked(QTreeWidgetItem *item, int column)
{
    QString id=item->text(0);
    idx=treeItemIno[id];
    ui->downBtn->setEnabled(true);
}

void LyricSearchWidget::onDownClicked()
{
    QString artist=artists[idx];
    QString title=titles[idx];
    QString id=ids[idx];
    downloadLyric(id,title,artist);
}

void LyricSearchWidget::onItemDblClicked(QTreeWidgetItem *item, int column)
{
    ui->downBtn->setEnabled(true);
    onDownClicked();
}

void LyricSearchWidget::onSearchClicked()
{
    ui->treeWidget->clear();
    ui->downBtn->setEnabled(false);
    searchLyric(ti,ar);
}

char* LyricSearchWidget::hexString(const QString &str_array)
{
    int len=str_array.length();
    const int length=4*len+1;
    char *hexStr=(char*)malloc(length);
    char *str=hexStr;
    char hexBase[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
    for(int i=0;i<len;i++)
    {
        int a,b,c,d;
        ushort u=str_array.at(i).unicode();        //16 bit unicode of each character
        a=(int)(u&0x00FF);              //f**k!!!
        b=(int)((u&0xFF00)>>8);
        c=((unsigned char)a)/16;     //important!
        d=((unsigned char)a)%16;
        (*hexStr)=hexBase[c]; ++hexStr;
        (*hexStr)=hexBase[d]; ++hexStr;
        c=((unsigned char)b/16);
        d=((unsigned char)b%16);
        (*hexStr)=hexBase[c];++hexStr;
        (*hexStr)=hexBase[d];++hexStr;
    }
    (*hexStr)='\0';
    return str;
}
